<template>
  <div class="cloudmeter-monitor">
    <!-- 页面标题 -->
    <div class="page-header">
      <h2>云测仪监控系统</h2>
      <div class="header-actions">
        <el-button type="primary" icon="el-icon-refresh" @click="refreshData">刷新数据</el-button>
        <el-button type="success" icon="el-icon-download" @click="exportData">导出数据</el-button>
      </div>
    </div>

    <!-- 田字形布局的4个模块 -->
    <div class="monitor-grid">
      <!-- 第一个模块：云测仪控制（按需求重构） -->
      <div class="grid-item device-control">
        <!-- 顶部区域：标题 + 离线标识 + 下拉框 + 参数配置按钮 -->
        <div class="module-header device-control-header">
          <div class="header-left">
            <!-- 标题：云测仪 -->
            <span class="title">云测仪</span>
            <!-- 红色离线状态标识 -->
            <span class="status-badge offline">离线</span>
          </div>
          <div class="header-right">
            <!-- 下拉框：默认选项为 区域控制器 - 空气质量云... -->
            <el-select
              v-model="selectedController"
              size="mini"
              class="controller-select"
              placeholder="请选择控制器"
              @change="onControllerChange"
            >
              <el-option
                v-for="opt in controllerOptions"
                :key="opt"
                :label="opt"
                :value="opt"
              />
            </el-select>
            <!-- 右上角参数配置按钮 -->
            <el-button size="mini" type="primary" class="config-btn" @click="openParamConfig">
              参数配置
            </el-button>
          </div>
        </div>

        <!-- 中间区域：温度阈值 与 湿度阈值 两个分块 -->
        <div class="module-content device-control-content">
          <div class="threshold-cards">
            <!-- 温度阈值模块（改为显示接口数据） -->
            <div class="threshold-card temperature">
              <div class="icon-wrap">
                <!-- 使用太阳图标表示温度 -->
                <i class="el-icon-sunny"></i>
              </div>
              <div class="value-wrap">
                <!-- 显示接口 /cloudMeter/device/manage 返回的阈值范围 -->
                <div class="value">{{ temThresholdText }}</div>
                <div class="label">温度阈值</div>
              </div>
            </div>

            <!-- 湿度阈值模块（改为显示接口数据） -->
            <div class="threshold-card humidity">
              <div class="icon-wrap">
                <!-- 使用水杯图标近似表示湿度（水滴图标不可用时采用替代） -->
                <i class="el-icon-water-cup"></i>
              </div>
              <div class="value-wrap">
                <!-- 显示接口 /cloudMeter/device/manage 返回的阈值范围 -->
                <div class="value">{{ humThresholdText }}</div>
                <div class="label">湿度阈值</div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 第二个模块：设备状态 -->
      <div class="grid-item device-status-detail">
        <div class="module-header">
          <i class="el-icon-monitor"></i>
          <span>设备状态</span>
        </div>
        <div class="module-content">
          <!-- 环境参数显示 -->
          <div class="environment-params">
            <!-- 温度 -->
            <div class="param-item temperature">
              <div class="param-icon">
                <i class="el-icon-sunny"></i>
              </div>
              <div class="param-content">
                <div class="param-value">0°C</div>
                <div class="param-label">温度</div>
              </div>
            </div>

            <!-- 湿度 -->
            <div class="param-item humidity">
              <div class="param-icon">
                <i class="el-icon-partly-cloudy"></i>
              </div>
              <div class="param-content">
                <div class="param-value">0%RH</div>
                <div class="param-label">湿度</div>
              </div>
            </div>

            <!-- PM2.5 -->
            <div class="param-item pm25">
              <div class="param-icon">
                <i class="el-icon-heavy-rain"></i>
              </div>
              <div class="param-content">
                <div class="param-value">0</div>
                <div class="param-label">PM2.5</div>
              </div>
            </div>
          </div>

          <!-- 气体浓度指示条 -->
          <div class="gas-indicators">
            <div class="gas-item">
              <div class="gas-label">CO2</div>
              <div class="gas-bar">
                <div class="gas-progress" style="width: 0%"></div>
              </div>
            </div>
            <div class="gas-item">
              <div class="gas-label">CH2O</div>
              <div class="gas-bar">
                <div class="gas-progress" style="width: 0%"></div>
              </div>
            </div>
            <div class="gas-item">
              <div class="gas-label">PM10</div>
              <div class="gas-bar">
                <div class="gas-progress" style="width: 0%"></div>
              </div>
            </div>
            <div class="gas-item">
              <div class="gas-label">TVOC</div>
              <div class="gas-bar">
                <div class="gas-progress" style="width: 0%"></div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 第三个模块：温湿度曲线 -->
      <div class="grid-item temperature-humidity-chart">
        <div class="module-header">
          <i class="el-icon-data-line"></i>
          <span>温湿度曲线</span>
          <div class="header-controls">
            <el-button size="mini" type="primary" @click="refreshTempHumData">刷新</el-button>
          </div>
        </div>
        <div class="module-content">
          <!-- 温湿度图表 -->
          <div class="temp-hum-chart-container">
            <div id="tempHumChart" ref="tempHumChart" class="temp-hum-chart" v-loading="tempHumLoading"></div>
          </div>
          
          <!-- 温湿度统计 -->
          <div class="temp-hum-stats">
            <div class="stat-group">
              <div class="stat-item temperature">
                <div class="stat-label">当前温度</div>
                <div class="stat-value">{{ getCurrentTemp() }}°C</div>
              </div>
              <div class="stat-item humidity">
                <div class="stat-label">当前湿度</div>
                <div class="stat-value">{{ getCurrentHum() }}%</div>
              </div>
            </div>
            <div class="stat-group">
              <div class="stat-item temperature">
                <div class="stat-label">平均温度</div>
                <div class="stat-value">{{ getAverageTemp() }}°C</div>
              </div>
              <div class="stat-item humidity">
                <div class="stat-label">平均湿度</div>
                <div class="stat-value">{{ getAverageHum() }}%</div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 第四个模块：空气质量曲线 -->
      <div class="grid-item air-quality-chart">
        <div class="module-header">
          <i class="el-icon-data-line"></i>
          <span>空气质量曲线</span>
          <div class="header-controls">
            <el-button size="mini" type="primary" @click="refreshChartData" :loading="chartLoading">
              <i class="el-icon-refresh"></i>
            </el-button>
          </div>
        </div>
        <div class="module-content">
          <!-- 图表容器 -->
          <div class="chart-container" ref="airQualityChart" v-loading="chartLoading"></div>
          
          <!-- 数据统计 -->
          <div class="chart-stats">
            <div class="stat-item">
              <span class="stat-label">当前值</span>
              <span class="stat-value" :class="getMetricClass(selectedMetric)">
                {{ getCurrentValue() }}{{ getMetricUnit(selectedMetric) }}
              </span>
            </div>
            <div class="stat-item">
              <span class="stat-label">平均值</span>
              <span class="stat-value">
                {{ getAverageValue() }}{{ getMetricUnit(selectedMetric) }}
              </span>
            </div>
            <div class="stat-item">
              <span class="stat-label">最高值</span>
              <span class="stat-value">
                {{ getMaxValue() }}{{ getMetricUnit(selectedMetric) }}
              </span>
            </div>
            <div class="stat-item">
              <span class="stat-label">最低值</span>
              <span class="stat-value">
                {{ getMinValue() }}{{ getMetricUnit(selectedMetric) }}
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 编辑详情弹窗（新增） -->
    <el-dialog
      :visible.sync="showEditDialog"
      width="720px"
      class="edit-dialog"
      :close-on-click-modal="false"
      :destroy-on-close="true"
      title="编辑详情"
    >
      <!-- 多列表单布局 -->
      <el-form
        ref="editFormRef"
        :model="editForm"
        :rules="editRules"
        label-width="100px"
        label-position="right"
        size="small"
        class="edit-form-grid"
      >
        <!-- 第一列组 -->
        <div class="form-grid">
          <!-- 设备类型：只读下拉，固定值云测仪 -->
          <el-form-item label="设备类型">
            <!-- 只读下拉选择框 -->
            <el-select v-model="editForm.deviceType" disabled style="width: 100%">
              <el-option label="云测仪" value="云测仪" />
            </el-select>
          </el-form-item>

          <!-- 所属库房：只读下拉，必填 -->
          <el-form-item label="所属库房" prop="storeName" required>
            <el-select v-model="editForm.storeName" disabled style="width: 100%">
              <el-option :label="editForm.storeName || 'A库房'" :value="editForm.storeName || 'A库房'" />
            </el-select>
          </el-form-item>

          <!-- 设备名称：必填可编辑 -->
          <el-form-item label="设备名称" prop="deviceName" required>
            <el-input v-model="editForm.deviceName" placeholder="请输入设备名称" />
          </el-form-item>

          <!-- 设备编号：只读下拉 -->
          <el-form-item label="设备编号" prop="deviceAddrCode" required>
            <el-select v-model="editForm.deviceAddrCode" disabled style="width: 100%">
              <el-option :label="editForm.deviceAddrCode || '01'" :value="editForm.deviceAddrCode || '01'" />
            </el-select>
          </el-form-item>

          <!-- 温度阈值：区间输入框（上下限） -->
          <el-form-item label="温度阈值">
            <div class="range-inputs">
              <el-input v-model="editForm.temAlarmDown" placeholder="下限" />
              <span class="range-sep">-</span>
              <el-input v-model="editForm.temAlarmUp" placeholder="上限" />
              <span class="range-unit">℃</span>
            </div>
          </el-form-item>

          <!-- 湿度阈值：区间输入框（上下限） -->
          <el-form-item label="湿度阈值">
            <div class="range-inputs">
              <el-input v-model="editForm.humAlarmDown" placeholder="下限" />
              <span class="range-sep">-</span>
              <el-input v-model="editForm.humAlarmUp" placeholder="上限" />
              <span class="range-unit">% RH</span>
            </div>
          </el-form-item>

          <!-- 温度系数：输入框 -->
          <el-form-item label="温度系数">
            <el-input v-model="editForm.temAdjust" placeholder="0" />
          </el-form-item>

          <!-- 湿度系数：输入框 -->
          <el-form-item label="湿度系数">
            <el-input v-model="editForm.humAdjust" placeholder="0" />
          </el-form-item>

          <!-- 关联传感器：下拉选择，默认自身传感器 -->
          <el-form-item label="关联传感器">
            <el-select v-model="editForm.refSensorNo" placeholder="请选择" style="width: 100%">
              <!-- 映射：'自身传感器' => '0000'（后端字段refSensorNo） -->
              <el-option label="自身传感器" value="0000" />
              <el-option label="外置传感器1" value="0001" />
              <el-option label="外置传感器2" value="0002" />
            </el-select>
          </el-form-item>

          <!-- 修改方式：单选组 -->
          <el-form-item label="修改方式">
            <el-radio-group v-model="editForm.modifyMode">
              <el-radio label="single">本设备修改</el-radio>
              <el-radio label="batch">批量修改</el-radio>
            </el-radio-group>
          </el-form-item>
        </div>
      </el-form>

      <!-- 底部操作按钮 -->
      <span slot="footer" class="dialog-footer">
        <el-button @click="showEditDialog = false">取消</el-button>
        <el-button type="primary" @click="confirmEdit">确认</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import * as echarts from 'echarts'
import request from '@/utils/request'

export default {
  name: 'CloudmeterMonitor',
  data() {
    return {
      // 自动刷新
      autoRefresh: true,
      refreshTimer: null,
      
      // 设备状态
      deviceStatus: {
        online: 12,
        offline: 2,
        warning: 1
      },
      
      // 设备列表
      deviceList: [
        { id: 1, name: '云测仪-001', type: '温湿度传感器', status: 'online' },
        { id: 2, name: '云测仪-002', type: '气压传感器', status: 'online' },
        { id: 3, name: '云测仪-003', type: '风速传感器', status: 'warning' },
        { id: 4, name: '云测仪-004', type: '温湿度传感器', status: 'offline' },
        { id: 5, name: '云测仪-005', type: '综合传感器', status: 'online' }
      ],
      
      // 数据指标
      metrics: {
        temperature: 23.5,
        temperatureTrend: 'up',
        temperatureChange: 2.3,
        humidity: 65.2,
        humidityTrend: 'down',
        humidityChange: -1.8,
        pressure: 1013.2,
        pressureTrend: 'stable',
        pressureChange: 0.1,
        windSpeed: 3.2,
        windTrend: 'up',
        windChange: 5.6
      },
      
      // 时间范围选择
      selectedTimeRange: '24h',
      
      // 图表类型
      chartTypes: [
        { label: '温度', value: 'temperature' },
        { label: '湿度', value: 'humidity' },
        { label: '气压', value: 'pressure' },
        { label: '风速', value: 'windSpeed' }
      ],
      selectedChartType: 'temperature',
      lastUpdateTime: new Date().toLocaleString(),
      
      // 告警管理
      unreadAlarms: 3,
      alarmStats: {
        critical: 1,
        warning: 2,
        info: 5
      },
      recentAlarms: [
        {
          id: 1,
          title: '温度异常',
          description: '云测仪-003温度超出正常范围',
          level: 'critical',
          time: new Date(Date.now() - 300000),
          read: false,
          acknowledged: false
        },
        {
          id: 2,
          title: '设备离线',
          description: '云测仪-004连接中断',
          level: 'warning',
          time: new Date(Date.now() - 600000),
          read: false,
          acknowledged: false
        },
        {
          id: 3,
          title: '数据采集完成',
          description: '定时数据采集任务已完成',
          level: 'info',
          time: new Date(Date.now() - 900000),
          read: true,
          acknowledged: true
        }
      ],
      
      // 温湿度图表相关
      tempHumLoading: false,
      tempHumChartInstance: null,
      tempHumData: [],
      
      // 空气质量图表相关
      selectedMetric: 'tvoc',
      chartLoading: false,
      chartData: [],
      chartInstance: null,
      
      // 系统配置
      activeConfigTab: 'collection',
      config: {
        collectionInterval: 30,
        dataRetentionDays: 30,
        autoBackup: true,
        tempThreshold: { min: 0, max: 40 },
        humidityThreshold: { min: 30, max: 80 },
        notificationMethods: ['email'],
        refreshInterval: 30,
        theme: 'light',
        enableAnimations: true
      },
      
      // 系统信息
      systemUptime: '3天 12小时 45分钟',
      totalDataPoints: 125680
      ,
      // 顶部下拉选择：控制器选项与默认值（新增）
      // 顶部下拉：选中的设备（使用后端返回的 alias）
      selectedController: '',
      controllerOptions: [],

      // 编辑详情弹窗（新增）
      showEditDialog: false,
      // 表单数据：与后端字段映射保持一致（新增）
      editForm: {
        deviceType: '云测仪',
        storeName: 'A库房',
        deviceName: '空气质量云测仪_1',
        deviceAddrCode: '01',
        temAlarmDown: '0',
        temAlarmUp: '100',
        humAlarmDown: '0',
        humAlarmUp: '100',
        temAdjust: '0',
        humAdjust: '0',
        refSensorNo: '0000',
        modifyMode: 'single'
      },
      // 校验规则（新增）
      editRules: {
        storeName: [{ required: true, message: '所属库房为必填', trigger: 'change' }],
        deviceName: [{ required: true, message: '设备名称为必填', trigger: 'blur' }],
        deviceAddrCode: [{ required: true, message: '设备编号为必填', trigger: 'change' }]
      },
      // 设备管理列表缓存（新增）
      deviceManageList: []
    }
  },
  
  // 计算属性：根据顶部选择的 alias 获取当前设备，并生成阈值文本
  computed: {
    // 当前选中设备对象（来源：/cloudMeter/device/manage）
    currentDevice() {
      return this.deviceManageList.find(d => d.alias === this.selectedController) || null
    },
    // 温度阈值文本，例如 "0-100℃"
    temThresholdText() {
      if (!this.currentDevice) return '0-100℃'
      const down = this.currentDevice.temAlarmDown || '0'
      const up = this.currentDevice.temAlarmUp || '100'
      return `${down}-${up}℃`
    },
    // 湿度阈值文本，例如 "0-100% RH"
    humThresholdText() {
      if (!this.currentDevice) return '0-100% RH'
      const down = this.currentDevice.humAlarmDown || '0'
      const up = this.currentDevice.humAlarmUp || '100'
      return `${down}-${up}% RH`
    }
  },

  mounted() {
    this.startAutoRefresh()
    this.initChart()
    this.fetchChartData()
    this.initTempHumChart()
    // 初始化设备管理数据并填充顶部下拉（新增）
    this.fetchDeviceManageList()
  },
  
  beforeDestroy() {
    this.stopAutoRefresh()
    if (this.chartInstance) {
      this.chartInstance.dispose()
    }
    if (this.tempHumChartInstance) {
      this.tempHumChartInstance.dispose()
    }
  },
  
  methods: {
    // 构造图表接口入参（POST）
    buildChartPayload() {
      const d = this.currentDevice || {}
      // 入参格式 {storeId, deviceTypeCode, deviceAddrCode, termId, storeCode}
      return {
        storeId: d.storeId || 1,
        deviceTypeCode: d.deviceTypeCode || '04',
        deviceAddrCode: d.deviceAddrCode || '01',
        termId: d.termId || 1,
        storeCode: d.storeCode || 'A'
      }
    },

    // 兼容性提取 PM2.5 数值（处理大小写与异常键名，如空格键）
    getPM25Value(item) {
      // 优先候选键集合
      const candidates = [
        item.PM25,
        item.pm25,
        item['PM25'],
        item['PM2.5'],
        item['pm2_5'],
        item['PM_25'],
        item[' ']
      ]
      for (const v of candidates) {
        if (v != null && !isNaN(parseFloat(v))) return parseFloat(v)
      }
      // 扫描所有键，匹配 /pm\s*25/i
      for (const [k, v] of Object.entries(item)) {
        if (/pm\s*25/i.test(k) && v != null && !isNaN(parseFloat(v))) {
          return parseFloat(v)
        }
      }
      return null
    },

    // 兼容性提取 TVOC 数值（处理大小写）
    getTvocValue(item) {
      const v = item.tvoc != null ? item.tvoc : (item.TVOC != null ? item.TVOC : null)
      return v != null && !isNaN(parseFloat(v)) ? parseFloat(v) : null
    },
    // 刷新数据（接入设备管理接口）
    async refreshData() {
      // 先刷新设备管理数据，以便阈值与弹窗预填联动
      await this.fetchDeviceManageList()
      // 根据当前选择填充一次（确保编辑表单与展示一致）
      this.fillEditFormFromSelected()
      // 记录更新时间与提示
      this.lastUpdateTime = new Date().toLocaleString()
      this.$message.success('数据刷新成功（已同步设备管理数据）')
    },
    
    // 导出数据
    exportData() {
      this.$message.success('数据导出成功')
    },

    // 控制器选择变更（新增）
    onControllerChange(val) {
      // 当用户切换下拉框时提示信息
      this.$message.success(`已切换到：${val}`)
      // 同步编辑表单以及展示阈值
      this.fillEditFormFromSelected()
    },

    // 打开参数配置（新增）
    openParamConfig() {
      // 打开弹窗，并根据当前选择自动填充表单
      this.showEditDialog = true
      // 若设备列表为空，先拉取一次
      if (!this.deviceManageList.length) {
        this.fetchDeviceManageList().then(() => this.fillEditFormFromSelected())
      } else {
        this.fillEditFormFromSelected()
      }
    },

    // 拉取设备管理数据 /cloudMeter/device/manage（新增）
    async fetchDeviceManageList() {
      try {
        const res = await request({ url: '/cloudMeter/device/manage', method: 'get' })
        if (res && res.code === 200 && Array.isArray(res.data)) {
          this.deviceManageList = res.data
          // 用 alias 填充顶部下拉选项
          this.controllerOptions = res.data.map(item => item.alias)
          // 若当前未选择，则默认选中第一项
          if (!this.selectedController && this.controllerOptions.length) {
            this.selectedController = this.controllerOptions[0]
          }
        } else {
          console.warn('设备管理接口返回异常，使用已有默认选项')
        }
      } catch (e) {
        console.error('拉取设备管理数据失败:', e)
      }
    },

    // 根据顶部选择填充编辑表单（新增）
    fillEditFormFromSelected() {
      if (!this.selectedController) return
      const item = this.deviceManageList.find(d => d.alias === this.selectedController)
      if (!item) {
        // 若未匹配，保留默认表单
        this.$message.warning('未找到匹配的设备数据，使用默认参数')
        return
      }
      // 将后端字段映射到表单
      this.editForm.deviceType = item.deviceType || '云测仪'
      this.editForm.storeName = item.storeName || 'A库房'
      this.editForm.deviceName = item.deviceName || ''
      this.editForm.deviceAddrCode = item.deviceAddrCode || '01'
      this.editForm.temAlarmDown = item.temAlarmDown || '0'
      this.editForm.temAlarmUp = item.temAlarmUp || '100'
      this.editForm.humAlarmDown = item.humAlarmDown || '0'
      this.editForm.humAlarmUp = item.humAlarmUp || '100'
      this.editForm.temAdjust = item.temAdjust || '0'
      this.editForm.humAdjust = item.humAdjust || '0'
      this.editForm.refSensorNo = item.refSensorNo || '0000'
      // 修改方式默认本设备
      this.editForm.modifyMode = 'single'
    },

    // 确认提交（仅校验与演示映射，留待后续接入保存接口）（新增）
    // 构造接口所需的设备参数负载（新增）
    buildEditPayload() {
      // 当前选中设备（来自 /cloudMeter/device/manage）
      const item = this.currentDevice || {}
      // 修改方式：single => 0（本设备修改），batch => 1（批量修改）
      const modStatus = this.editForm.modifyMode === 'single' ? 0 : 1
      // 生成符合后端要求的参数结构
      return {
        deviceTypeCode: item.deviceTypeCode || '04',
        storeId: item.storeId || 1,
        deviceName: this.editForm.deviceName,
        deviceAddrCode: this.editForm.deviceAddrCode || item.deviceAddrCode || '01',
        temAlarmDown: this.editForm.temAlarmDown,
        temAlarmUp: this.editForm.temAlarmUp,
        humAlarmDown: this.editForm.humAlarmDown,
        humAlarmUp: this.editForm.humAlarmUp,
        temAdjust: this.editForm.temAdjust,
        humAdjust: this.editForm.humAdjust,
        refSensorNo: this.editForm.refSensorNo,
        modStatus: modStatus,
        termId: item.termId || 1,
        deviceType: item.deviceType || this.editForm.deviceType || '云测仪'
      }
    },

    // 确认提交：校验并调用 PUT /cloudMeter/device/manage/{id}（新增）
    confirmEdit() {
      this.$refs.editFormRef.validate(async valid => {
        if (!valid) return
        try {
          // 选中设备的 id 作为路径参数
          const id = this.currentDevice && this.currentDevice.id
          if (!id) {
            this.$message.error('当前未选择设备或设备缺少ID')
            return
          }
          const payload = this.buildEditPayload()
          // 调用后端保存接口（PUT）
          const res = await request({
            url: `/cloudMeter/device/manage/${id}`,
            method: 'put',
            data: payload
          })
          if (res && res.code === 200) {
            this.$message.success('参数保存成功')
            this.showEditDialog = false
            // 重新拉取列表并同步当前展示
            await this.fetchDeviceManageList()
            this.fillEditFormFromSelected()
          } else {
            this.$message.error(res && res.msg ? res.msg : '保存失败')
          }
        } catch (e) {
          console.error('保存接口调用失败:', e)
          this.$message.error('保存接口调用失败')
        }
      })
    },
    
    // 自动刷新控制
    startAutoRefresh() {
      if (this.autoRefresh) {
        this.refreshTimer = setInterval(() => {
          this.refreshData()
          this.fetchChartData()
        }, 30000) // 30秒刷新一次
      }
    },
    
    stopAutoRefresh() {
      if (this.refreshTimer) {
        clearInterval(this.refreshTimer)
        this.refreshTimer = null
      }
    },
    
    // 设备相关方法
    getStatusText(status) {
      const statusMap = {
        online: '在线',
        offline: '离线',
        warning: '告警'
      }
      return statusMap[status] || '未知'
    },
    
    selectDevice(device) {
      this.$message.info(`选择设备：${device.name}`)
    },
    
    showDeviceDetail() {
      this.$message.info('显示设备详情')
    },
    
    // 数据分析相关方法
    updateTimeRange() {
      this.$message.success(`时间范围已更新为：${this.selectedTimeRange}`)
      this.refreshData()
    },
    
    getTrendIcon(trend) {
      const iconMap = {
        up: 'el-icon-top',
        down: 'el-icon-bottom',
        stable: 'el-icon-minus'
      }
      return iconMap[trend] || 'el-icon-minus'
    },
    
    changeChartType(type) {
      this.selectedChartType = type
      this.$message.success(`切换到${type}图表`)
    },
    
    // 告警相关方法
    markAllRead() {
      this.recentAlarms.forEach(alarm => {
        alarm.read = true
      })
      this.unreadAlarms = 0
      this.$message.success('所有告警已标记为已读')
    },
    
    showAllAlarms() {
      this.$message.info('显示所有告警')
    },
    
    getAlarmIcon(level) {
      const iconMap = {
        critical: 'el-icon-warning',
        warning: 'el-icon-info',
        info: 'el-icon-message'
      }
      return iconMap[level] || 'el-icon-info'
    },
    
    handleAlarm(alarm) {
      this.$message.info(`处理告警：${alarm.title}`)
    },
    
    acknowledgeAlarm(alarm) {
      alarm.acknowledged = !alarm.acknowledged
      this.$message.success(alarm.acknowledged ? '告警已确认' : '取消确认')
    },
    
    formatTime(time) {
      const now = new Date()
      const diff = now - time
      const minutes = Math.floor(diff / 60000)
      
      if (minutes < 1) return '刚刚'
      if (minutes < 60) return `${minutes}分钟前`
      
      const hours = Math.floor(minutes / 60)
      if (hours < 24) return `${hours}小时前`
      
      const days = Math.floor(hours / 24)
      return `${days}天前`
    },
    
    // 空气质量图表相关方法
    async fetchChartData() {
      this.chartLoading = true
      try {
        // 根据当前选择设备构造 POST 入参
        const payload = this.buildChartPayload()
        console.log('调用空气质量曲线 POST /cloudMeter/device/detail/chart, 入参:', payload)
        const response = await request({
          url: '/cloudMeter/device/detail/chart',
          method: 'post',
          data: payload
        })
        // 处理后端返回的标准格式：{ code: 200, msg: "请求成功", data: [...] }
        if (response && (response.code === 200 || response.code === '200')) {
          // 规范化数据：修复 PM2.5 键名异常（如空字符串键" ")并统一数值类型
          this.chartData = this.normalizeChartData(response.data || [])
          // 同步温湿度图表使用同一数据
          this.tempHumData = this.chartData
          this.updateChart()
          this.updateTempHumChart(this.chartData)
        } else {
          console.warn('空气质量曲线接口返回异常，使用模拟数据', response && response.msg)
          this.useMockData()
          // 使用模拟数据时也同步温湿度图表
          this.tempHumData = this.chartData
          this.updateTempHumChart(this.chartData)
        }
      } catch (error) {
        console.error('空气质量曲线接口调用失败:', error)
        this.useMockData()
        // 使用模拟数据时也同步温湿度图表
        this.tempHumData = this.chartData
        this.updateTempHumChart(this.chartData)
      } finally {
        this.chartLoading = false
      }
    },

    // 规范化接口返回的数据（修复异常键名并统一数值类型）
    normalizeChartData(raw) {
      if (!Array.isArray(raw)) return []
      return raw.map(item => {
        // PM2.5 可能出现在 PM25、pm25 或异常键名 " " 中
        const pmRaw = item.PM25 != null ? item.PM25 : (item.pm25 != null ? item.pm25 : (item[' '] != null ? item[' '] : null))
        // TVOC 可能出现在 tvoc 或 TVOC 中
        const tvRaw = item.tvoc != null ? item.tvoc : (item.TVOC != null ? item.TVOC : null)
        const time = item.time != null ? String(item.time) : ''
        return {
          // 保留常用字段，统一数值类型
          time,
          timeStamp: item.timeStamp,
          tem: item.tem,
          hum: item.hum,
          eco2: item.eco2,
          PM25: pmRaw != null ? parseFloat(pmRaw) : null,
          tvoc: tvRaw != null ? parseFloat(tvRaw) : null
        }
      })
    },

    // 使用模拟数据的方法
    useMockData() {
      this.chartData = [
        { tvoc: 4485.4, timeStamp: "1747790333319", hum: 58.2, PM25: 57.0, time: "09", tem: 25.0, eco2: 529.4 },
        { tvoc: 3573.5, timeStamp: "1747793013561", hum: 55.5, PM25: 49.4, time: "10", tem: 25.0, eco2: 514.3 },
        { tvoc: 3204.5, timeStamp: "1747796409528", hum: 51.8, PM25: 37.2, time: "11", tem: 25.8, eco2: 511.5 },
        { tvoc: 2658.8, timeStamp: "1747800038809", hum: 47.8, PM25: 31.7, time: "12", tem: 26.2, eco2: 490.7 },
        { tvoc: 3128.3, timeStamp: "1747803662547", hum: 47.7, PM25: 36.8, time: "13", tem: 27.0, eco2: 522.7 },
        { tvoc: 3174.3, timeStamp: "1747807292303", hum: 49.3, PM25: 42.0, time: "14", tem: 27.2, eco2: 531.2 },
        { tvoc: 4324.0, timeStamp: "1747810915844", hum: 50.5, PM25: 49.3, time: "15", tem: 28.0, eco2: 593.5 }
      ]
      this.updateChart()
    },
    
    refreshChartData() {
      this.fetchChartData()
    },
    
    initChart() {
      this.$nextTick(() => {
        if (this.$refs.airQualityChart) {
          this.chartInstance = echarts.init(this.$refs.airQualityChart)
          this.updateChart()
        }
      })
    },
    
    // 更新空气质量曲线：同时显示 PM2.5 与 TVOC 两条曲线（右侧 TVOC 固定刻度）
    updateChart() {
      if (!this.chartInstance || !this.chartData.length) return

      // 横坐标：直接使用后端返回的 time（如 "09"），保持与数据一致
      const times = this.chartData.map(item => (item.time != null ? String(item.time) : ''))

      // 两条曲线的数据源（兼容大小写字段）
      // 兼容多种字段名与异常键名的数值提取
      const pm25Values = this.chartData.map(item => this.getPM25Value(item))
      const tvocValues = this.chartData.map(item => this.getTvocValue(item))

      // 动态计算 TVOC 的最大值，若超出 1800 则按 300 的倍数上调到可见范围
      const tvocValid = tvocValues.filter(v => typeof v === 'number' && isFinite(v))
      const tvocMaxValue = tvocValid.length ? Math.max(...tvocValid) : 1800
      const tvocMaxAxis = Math.max(1800, Math.ceil(tvocMaxValue / 300) * 300)

      const option = {
        title: {
          text: '空气质量曲线（PM2.5 & TVOC）',
          left: 'center',
          textStyle: { fontSize: 14, fontWeight: 'normal' }
        },
        legend: { data: ['PM2.5', 'TVOC'], top: 30 },
        tooltip: {
          trigger: 'axis',
          // 同时展示两条曲线的数值与单位
          formatter: (params) => {
            const name = params[0] ? params[0].name : ''
            const pm = params.find(p => p.seriesName === 'PM2.5')
            const tv = params.find(p => p.seriesName === 'TVOC')
            const pmText = pm && pm.value != null ? `${pm.marker}PM2.5：${pm.value} μg/m³` : ''
            const tvText = tv && tv.value != null ? `${tv.marker}TVOC：${tv.value} ppb` : ''
            return `${name} 时<br/>${pmText}${pmText && tvText ? '<br/>' : ''}${tvText}`
          }
        },
        grid: { left: '3%', right: '4%', bottom: '3%', top: '15%', containLabel: true },
        xAxis: { type: 'category', boundaryGap: false, data: times, axisLabel: { fontSize: 10 } },
        // 双 Y 轴：左侧 PM2.5（μg/m³）自动刻度，右侧 TVOC（ppb）固定刻度
        yAxis: [
          {
            type: 'value', name: 'PM2.5(μg/m³)', position: 'left',
            axisLabel: { formatter: '{value} μg/m³', fontSize: 10 },
            splitLine: { show: true, lineStyle: { color: '#f0f0f0' } }
          },
          {
            type: 'value', name: 'TVOC(ppb)', position: 'right',
            min: 0, max: tvocMaxAxis, interval: 300,
            axisLabel: { fontSize: 10, formatter: '{value}' },
            splitLine: { show: false }
          }
        ],
        series: [
          {
            name: 'PM2.5', type: 'line', yAxisIndex: 0, data: pm25Values,
            smooth: true, symbol: 'circle', symbolSize: 6,
            lineStyle: { width: 2, color: this.getMetricColor('PM25') },
            itemStyle: { color: this.getMetricColor('PM25') },
            areaStyle: {
              color: {
                type: 'linear', x: 0, y: 0, x2: 0, y2: 1,
                colorStops: [
                  { offset: 0, color: this.getMetricColor('PM25') + '40' },
                  { offset: 1, color: this.getMetricColor('PM25') + '10' }
                ]
              }
            }
          },
          {
            name: 'TVOC', type: 'line', yAxisIndex: 1, data: tvocValues,
            smooth: true, symbol: 'circle', symbolSize: 6,
            lineStyle: { width: 2, color: this.getMetricColor('tvoc') },
            itemStyle: { color: this.getMetricColor('tvoc') },
            areaStyle: {
              color: {
                type: 'linear', x: 0, y: 0, x2: 0, y2: 1,
                colorStops: [
                  { offset: 0, color: this.getMetricColor('tvoc') + '40' },
                  { offset: 1, color: this.getMetricColor('tvoc') + '10' }
                ]
              }
            }
          }
        ]
      }

      this.chartInstance.setOption(option)
    },
    
    getMetricName(metric) {
      const names = {
        tem: '温度',
        hum: '湿度',
        PM25: 'PM2.5',
        tvoc: 'TVOC',
        eco2: 'eCO2'
      }
      return names[metric] || metric
    },
    
    getMetricUnit(metric) {
      const units = {
        tem: '°C',
        hum: '%',
        PM25: 'μg/m³',
        tvoc: 'ppb',
        eco2: 'ppm'
      }
      return units[metric] || ''
    },
    
    getMetricColor(metric) {
      const colors = {
        tem: '#ff6b6b',
        hum: '#4ecdc4',
        PM25: '#45b7d1',
        tvoc: '#f9ca24',
        eco2: '#6c5ce7'
      }
      return colors[metric] || '#409EFF'
    },
    
    getMetricClass(metric) {
      return `metric-${metric}`
    },
    
    getCurrentValue() {
      // 仅统计 TVOC（已固定为空气质量曲线主指标）
      if (!this.chartData.length) return '--'
      const values = this.chartData
        .map(d => this.getTvocValue(d))
        .filter(v => typeof v === 'number' && isFinite(v))
      if (!values.length) return '--'
      return values[values.length - 1].toFixed(1)
    },
    
    getAverageValue() {
      if (!this.chartData.length) return '--'
      const values = this.chartData
        .map(d => this.getTvocValue(d))
        .filter(v => typeof v === 'number' && isFinite(v))
      if (!values.length) return '--'
      const avg = values.reduce((sum, val) => sum + val, 0) / values.length
      return avg.toFixed(1)
    },
    
    getMaxValue() {
      if (!this.chartData.length) return '--'
      const values = this.chartData
        .map(d => this.getTvocValue(d))
        .filter(v => typeof v === 'number' && isFinite(v))
      if (!values.length) return '--'
      return Math.max(...values).toFixed(1)
    },
    
    getMinValue() {
      if (!this.chartData.length) return '--'
      const values = this.chartData
        .map(d => this.getTvocValue(d))
        .filter(v => typeof v === 'number' && isFinite(v))
      if (!values.length) return '--'
      return Math.min(...values).toFixed(1)
    },
    
    // 配置相关方法
    saveConfig() {
      this.$message.success('配置保存成功')
      
      // 重新启动自动刷新
      this.stopAutoRefresh()
      this.startAutoRefresh()
    },
    
    // 温湿度图表相关方法
    initTempHumChart() {
      this.$nextTick(() => {
        const chartDom = document.getElementById('tempHumChart')
        if (!chartDom) return
        
        this.tempHumChartInstance = echarts.init(chartDom)
        // 若已获取空气质量接口数据，则直接渲染温湿度曲线
        if (this.chartData && this.chartData.length) {
          this.tempHumData = this.chartData
          this.updateTempHumChart(this.chartData)
        }
      })
    },
    
    async fetchTempHumData() {
      // 只复用同一次接口数据：若未获取则调用 fetchChartData
      this.tempHumLoading = true
      try {
        if (!this.chartData.length) {
          await this.fetchChartData()
        }
        this.tempHumData = this.chartData
        this.updateTempHumChart(this.chartData)
      } finally {
        this.tempHumLoading = false
      }
    },
    
    useMockTempHumData() {
      console.log('使用温湿度模拟数据')
      // 使用用户提供的真实数据格式
      const mockData = [
        { tvoc: 4485.4, timeStamp: "1747790333319", hum: 58.2, PM25: 57.0, time: "09", tem: 25.0, eco2: 529.4 },
        { tvoc: 3573.5, timeStamp: "1747793013561", hum: 55.5, PM25: 49.4, time: "10", tem: 25.0, eco2: 514.3 },
        { tvoc: 3204.5, timeStamp: "1747796409528", hum: 51.8, PM25: 37.2, time: "11", tem: 25.8, eco2: 511.5 },
        { tvoc: 2658.8, timeStamp: "1747800038809", hum: 47.8, PM25: 31.7, time: "12", tem: 26.2, eco2: 490.7 },
        { tvoc: 3128.3, timeStamp: "1747803662547", hum: 47.7, PM25: 36.8, time: "13", tem: 27.0, eco2: 522.7 },
        { tvoc: 3174.3, timeStamp: "1747807292303", hum: 49.3, PM25: 42.0, time: "14", tem: 27.2, eco2: 531.2 },
        { tvoc: 4324.0, timeStamp: "1747810915844", hum: 50.5, PM25: 49.3, time: "15", tem: 28.0, eco2: 593.5 }
      ]
      this.tempHumData = mockData
      this.updateTempHumChart(mockData)
    },
    
    updateTempHumChart(data) {
      if (!this.tempHumChartInstance || !data.length) return
      
      // 使用timeStamp作为横坐标，转换为可读的时间格式
      const times = data.map(item => {
        // 将timeStamp转换为Date对象，然后格式化为时间字符串
        const timestamp = parseInt(item.timeStamp)
        const date = new Date(timestamp)
        return date.getHours().toString().padStart(2, '0') + ':' + 
               date.getMinutes().toString().padStart(2, '0')
      })
      
      const temValues = data.map(item => parseFloat(item.tem))
      const humValues = data.map(item => parseFloat(item.hum))
      
      const option = {
        title: {
          text: '温湿度曲线',
          left: 'center',
          textStyle: {
            fontSize: 14,
            color: '#333'
          }
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'cross'
          },
          formatter: function(params) {
            let result = params[0].name + '<br/>'
            params.forEach(param => {
              const unit = param.seriesName === '温度' ? '°C' : '%'
              result += param.marker + param.seriesName + ': ' + param.value + unit + '<br/>'
            })
            return result
          }
        },
        legend: {
          data: ['温度', '湿度'],
          top: 30
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          top: '15%',
          containLabel: true
        },
        xAxis: {
          type: 'category',
          boundaryGap: false,
          data: times,
          axisLabel: {
            fontSize: 10
          }
        },
        yAxis: [
          {
            type: 'value',
            name: '温度(°C)',
            position: 'left',
            min: 0,
            max: 60,
            interval: 10,
            axisLabel: {
              formatter: '{value}°C',
              fontSize: 10
            }
          },
          {
            type: 'value',
            name: '湿度(%)',
            position: 'right',
            min: 0,
            max: 60,
            interval: 10,
            axisLabel: {
              formatter: '{value}%',
              fontSize: 10
            }
          }
        ],
        series: [
          {
            name: '温度',
            type: 'line',
            yAxisIndex: 0,
            data: temValues,
            smooth: true,
            lineStyle: {
              color: '#ff6b6b',
              width: 2
            },
            itemStyle: {
              color: '#ff6b6b'
            },
            areaStyle: {
              color: {
                type: 'linear',
                x: 0,
                y: 0,
                x2: 0,
                y2: 1,
                colorStops: [{
                  offset: 0,
                  color: '#ff6b6b40'
                }, {
                  offset: 1,
                  color: '#ff6b6b10'
                }]
              }
            }
          },
          {
            name: '湿度',
            type: 'line',
            yAxisIndex: 1,
            data: humValues,
            smooth: true,
            lineStyle: {
              color: '#4ecdc4',
              width: 2
            },
            itemStyle: {
              color: '#4ecdc4'
            },
            areaStyle: {
              color: {
                type: 'linear',
                x: 0,
                y: 0,
                x2: 0,
                y2: 1,
                colorStops: [{
                  offset: 0,
                  color: '#4ecdc440'
                }, {
                  offset: 1,
                  color: '#4ecdc410'
                }]
              }
            }
          }
        ]
      }
      
      this.tempHumChartInstance.setOption(option)
    },
    
    refreshTempHumData() {
      // 统一刷新：只调用一次接口，并同步两类图表
      this.fetchChartData()
      this.$message.success('温湿度与空气质量数据已刷新')
    },
    
    // 温湿度统计方法
    getCurrentTemp() {
      if (!this.tempHumData.length) return '--'
      const lastData = this.tempHumData[this.tempHumData.length - 1]
      return lastData.tem ? lastData.tem.toFixed(1) : '--'
    },
    
    getCurrentHum() {
      if (!this.tempHumData.length) return '--'
      const lastData = this.tempHumData[this.tempHumData.length - 1]
      return lastData.hum ? lastData.hum.toFixed(1) : '--'
    },
    
    getAverageTemp() {
      if (!this.tempHumData.length) return '--'
      const values = this.tempHumData.map(item => item.tem).filter(v => v != null)
      if (!values.length) return '--'
      const avg = values.reduce((sum, val) => sum + val, 0) / values.length
      return avg.toFixed(1)
    },
    
    getAverageHum() {
      if (!this.tempHumData.length) return '--'
      const values = this.tempHumData.map(item => item.hum).filter(v => v != null)
      if (!values.length) return '--'
      const avg = values.reduce((sum, val) => sum + val, 0) / values.length
      return avg.toFixed(1)
    }
  },
  
  watch: {
    autoRefresh(newVal) {
      if (newVal) {
        this.startAutoRefresh()
      } else {
        this.stopAutoRefresh()
      }
    },
    
    selectedMetric() {
      this.updateChart()
    },
    // 监听顶部选择变化，联动编辑表单与展示文案
    selectedController() {
      this.fillEditFormFromSelected()
      // 切换设备时只调用一次接口以更新两类图表
      this.fetchChartData()
    }
  }
}
</script>

<style lang="scss" scoped>
.cloudmeter-monitor {
  padding: 20px;
  background: #f5f7fa;
  min-height: 100vh;
}

.page-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding: 0 10px;
  
  h2 {
    margin: 0;
    color: #333;
    font-size: 24px;
    font-weight: 600;
  }
  
  .header-actions {
    display: flex;
    gap: 10px;
  }
}

.monitor-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 20px;
  height: calc(100vh - 160px);
}

.grid-item {
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: all 0.3s ease;
  
  &:hover {
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
    transform: translateY(-2px);
  }
}

.module-header {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  padding: 15px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-weight: 500;
  
  i {
    margin-right: 8px;
    font-size: 16px;
  }
  
  .header-controls {
    display: flex;
    align-items: center;
    gap: 10px;
    
    .el-switch {
      :deep(.el-switch__label) {
        color: white;
      }
    }
  }
}

.module-content {
  flex: 1;
  padding: 20px;
  overflow: auto;
}

/* 设备状态模块样式 */
.device-status .module-header {
  background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
}

.status-overview {
  margin-bottom: 20px;
}

.status-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 15px;
  margin-bottom: 20px;
}

.status-card {
  background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
  border-radius: 8px;
  padding: 15px;
  color: white;
  display: flex;
  align-items: center;
  transition: all 0.3s ease;
  
  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
  }
  
  &.online {
    background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
  }
  
  &.offline {
    background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
  }
  
  &.warning {
    background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
    color: #333;
  }
  
  .card-icon {
    font-size: 24px;
    margin-right: 15px;
  }
  
  .card-content {
    flex: 1;
    
    .card-title {
      font-size: 12px;
      opacity: 0.8;
      margin-bottom: 5px;
    }
    
    .card-value {
      font-size: 24px;
      font-weight: bold;
    }
  }
}

.device-list {
  .list-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 15px;
    padding-bottom: 10px;
    border-bottom: 1px solid #eee;
    
    span {
      font-weight: 500;
      color: #333;
    }
  }
  
  .device-items {
    max-height: 200px;
    overflow-y: auto;
  }
  
  .device-item {
    padding: 12px;
    border: 1px solid #e8e8e8;
    border-radius: 6px;
    margin-bottom: 8px;
    cursor: pointer;
    transition: all 0.3s ease;
    
    &:hover {
      border-color: #409eff;
      background: #f0f9ff;
    }
    
    &.online {
      border-left: 4px solid #67c23a;
    }
    
    &.offline {
      border-left: 4px solid #f56c6c;
    }
    
    &.warning {
      border-left: 4px solid #e6a23c;
    }
    
    .device-name {
      font-weight: 500;
      margin-bottom: 5px;
    }
    
    .device-info {
      display: flex;
      justify-content: space-between;
      font-size: 12px;
      color: #666;
      
      .device-status {
        &.online { color: #67c23a; }
        &.offline { color: #f56c6c; }
        &.warning { color: #e6a23c; }
      }
    }
  }
}

/* 数据分析模块样式 */
.data-analysis .module-header {
  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}

.metrics-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 15px;
  margin-bottom: 20px;
}

.metric-card {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border-radius: 8px;
  padding: 15px;
  color: white;
  display: flex;
  align-items: center;
  transition: all 0.3s ease;
  
  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
  }
  
  &.temperature {
    background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);
  }
  
  &.humidity {
    background: linear-gradient(135deg, #74b9ff 0%, #0984e3 100%);
  }
  
  &.pressure {
    background: linear-gradient(135deg, #a29bfe 0%, #6c5ce7 100%);
  }
  
  &.wind {
    background: linear-gradient(135deg, #fd79a8 0%, #e84393 100%);
  }
  
  .metric-icon {
    font-size: 24px;
    margin-right: 15px;
  }
  
  .metric-content {
    flex: 1;
    
    .metric-label {
      font-size: 12px;
      opacity: 0.8;
      margin-bottom: 5px;
    }
    
    .metric-value {
      font-size: 20px;
      font-weight: bold;
      margin-bottom: 5px;
    }
    
    .metric-trend {
      font-size: 11px;
      display: flex;
      align-items: center;
      gap: 3px;
      
      &.up { color: #00ff88; }
      &.down { color: #ff6b6b; }
      &.stable { color: #ffd93d; }
    }
  }
}

.chart-container {
  .chart-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 15px;
    
    span {
      font-weight: 500;
      color: #333;
    }
  }
  
  .chart-placeholder {
    height: 200px;
    background: #f8f9fa;
    border-radius: 8px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: #666;
    
    .chart-icon {
      font-size: 48px;
      margin-bottom: 10px;
      opacity: 0.5;
    }
    
    p {
      margin: 5px 0;
      font-size: 16px;
    }
    
    small {
      font-size: 12px;
      opacity: 0.7;
    }
  }
}

/* 告警管理模块样式 */
.alarm-management .module-header {
  background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
}

.alarm-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 15px;
  margin-bottom: 20px;
}

.stat-item {
  background: #f8f9fa;
  border-radius: 8px;
  padding: 15px;
  display: flex;
  align-items: center;
  transition: all 0.3s ease;
  
  &:hover {
    background: #e9ecef;
  }
  
  &.critical {
    border-left: 4px solid #f56c6c;
  }
  
  &.warning {
    border-left: 4px solid #e6a23c;
  }
  
  &.info {
    border-left: 4px solid #409eff;
  }
  
  .stat-icon {
    font-size: 20px;
    margin-right: 12px;
    
    .critical & { color: #f56c6c; }
    .warning & { color: #e6a23c; }
    .info & { color: #409eff; }
  }
  
  .stat-content {
    .stat-label {
      font-size: 12px;
      color: #666;
      margin-bottom: 3px;
    }
    
    .stat-value {
      font-size: 18px;
      font-weight: bold;
      color: #333;
    }
  }
}

.alarm-list {
  .list-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 15px;
    padding-bottom: 10px;
    border-bottom: 1px solid #eee;
    
    span {
      font-weight: 500;
      color: #333;
    }
  }
  
  .alarm-items {
    max-height: 250px;
    overflow-y: auto;
  }
  
  .alarm-item {
    display: flex;
    align-items: flex-start;
    padding: 12px;
    border: 1px solid #e8e8e8;
    border-radius: 6px;
    margin-bottom: 8px;
    cursor: pointer;
    transition: all 0.3s ease;
    
    &:hover {
      background: #f8f9fa;
    }
    
    &.unread {
      background: #fff7e6;
      border-color: #ffd591;
    }
    
    &.critical {
      border-left: 4px solid #f56c6c;
    }
    
    &.warning {
      border-left: 4px solid #e6a23c;
    }
    
    &.info {
      border-left: 4px solid #409eff;
    }
    
    .alarm-icon {
      font-size: 16px;
      margin-right: 12px;
      margin-top: 2px;
      
      .critical & { color: #f56c6c; }
      .warning & { color: #e6a23c; }
      .info & { color: #409eff; }
    }
    
    .alarm-content {
      flex: 1;
      
      .alarm-title {
        font-weight: 500;
        margin-bottom: 3px;
      }
      
      .alarm-desc {
        font-size: 12px;
        color: #666;
        margin-bottom: 5px;
      }
      
      .alarm-time {
        font-size: 11px;
        color: #999;
      }
    }
    
    .alarm-actions {
      margin-left: 10px;
    }
  }
}

/* 空气质量图表模块样式 */
.air-quality-chart .module-header {
  background: linear-gradient(135deg, #74b9ff 0%, #0984e3 100%);
  
  .header-controls {
    .el-select {
      width: 120px;
      margin-right: 10px;
      
      :deep(.el-input__inner) {
        background: rgba(255, 255, 255, 0.2);
        border: 1px solid rgba(255, 255, 255, 0.3);
        color: white;
        
        &::placeholder {
          color: rgba(255, 255, 255, 0.7);
        }
      }
      
      :deep(.el-select__caret) {
        color: white;
      }
    }
    
    .el-button {
      background: rgba(255, 255, 255, 0.2);
      border: 1px solid rgba(255, 255, 255, 0.3);
      color: white;
      
      &:hover {
        background: rgba(255, 255, 255, 0.3);
      }
    }
  }
}

.chart-container {
  height: 300px;
  width: 100%;
  margin-bottom: 20px;
}

.chart-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 15px;
  
  .stat-item {
    background: #f8f9fa;
    border-radius: 8px;
    padding: 12px;
    text-align: center;
    transition: all 0.3s ease;
    
    &:hover {
      background: #e9ecef;
      transform: translateY(-2px);
    }
    
    .stat-label {
      display: block;
      font-size: 12px;
      color: #666;
      margin-bottom: 5px;
    }
    
    .stat-value {
      display: block;
      font-size: 16px;
      font-weight: 600;
      color: #333;
      
      &.metric-tem {
        color: #ff6b6b;
      }
      
      &.metric-hum {
        color: #4ecdc4;
      }
      
      &.metric-PM25 {
        color: #45b7d1;
      }
      
      &.metric-tvoc {
        color: #f9ca24;
      }
      
      &.metric-eco2 {
        color: #6c5ce7;
      }
    }
  }
}

/* 系统配置模块样式 */
.system-config .module-header {
  background: linear-gradient(135deg, #a29bfe 0%, #6c5ce7 100%);
}

.config-tabs {
  margin-bottom: 20px;
  
  :deep(.el-tabs__header) {
    margin-bottom: 15px;
  }
  
  :deep(.el-tabs__item) {
    font-size: 12px;
  }
}

/* 云测仪控制模块样式（新增） */
.device-control {
  /* 模块头部采用浅蓝主题 */
  .device-control-header {
    background: linear-gradient(135deg, #74b9ff 0%, #a5d8ff 100%);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px;

    .header-left {
      display: flex;
      align-items: center;
      gap: 10px;

      .title {
        font-size: 16px;
        font-weight: 600;
      }

      .status-badge {
        font-size: 12px;
        padding: 2px 8px;
        border-radius: 12px;
        background: #ffe3e3;
        border: 1px solid #ff7b7b;
        color: #d93025; /* 红色离线文字 */
      }
    }

    .header-right {
      display: flex;
      align-items: center;
      gap: 10px;

      .controller-select {
        width: 220px;
        :deep(.el-input__inner) {
          background: rgba(255, 255, 255, 0.2);
          border: 1px solid rgba(255, 255, 255, 0.4);
          color: #fff;
          &::placeholder { color: rgba(255, 255, 255, 0.85); }
        }
        :deep(.el-select__caret) { color: #fff; }
      }

      .config-btn {
        background: rgba(255, 255, 255, 0.2);
        border: 1px solid rgba(255, 255, 255, 0.4);
        color: #fff;
        &:hover { background: rgba(255, 255, 255, 0.3); }
      }
    }
  }

  .device-control-content {
    background: #ffffff;
    padding: 16px;

    .threshold-cards {
      display: grid;
      /* 改为单列网格：阈值卡片换行显示（不同行） */
      grid-template-columns: 1fr;
      gap: 16px;
    }

    .threshold-card {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 14px 16px;
      border: 1px solid #e8f0fe;
      border-radius: 10px;
      background: #f8fbff;
      box-shadow: 0 2px 10px rgba(116, 185, 255, 0.15);
      transition: box-shadow 0.2s ease, transform 0.2s ease;
      &:hover { box-shadow: 0 4px 16px rgba(116, 185, 255, 0.25); transform: translateY(-1px); }

      .icon-wrap {
        width: 44px;
        height: 44px;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        i { font-size: 20px; color: #fff; }
      }

      .value-wrap {
        display: flex;
        flex-direction: column;
        .value { font-size: 18px; font-weight: 600; }
        .label { font-size: 12px; color: #667; margin-top: 4px; }
      }

      &.temperature {
        .icon-wrap { background: linear-gradient(135deg, #67C23A, #85CE61); }
        .value-wrap .value { color: #67C23A; } /* 绿色温度数值 */
      }

      &.humidity {
        .icon-wrap { background: linear-gradient(135deg, #409EFF, #66B1FF); }
        .value-wrap .value { color: #409EFF; } /* 蓝色湿度数值 */
      }
    }
  }
}

/* 编辑详情弹窗样式（新增） */
.edit-dialog {
  :deep(.el-dialog__header) {
    background: linear-gradient(135deg, #74b9ff 0%, #a5d8ff 100%);
    color: #fff;
    padding: 14px 20px;
  }
  :deep(.el-dialog__title) {
    color: #fff;
    font-weight: 600;
  }
  :deep(.el-dialog__headerbtn .el-dialog__close) {
    color: #fff;
  }
}

.edit-form-grid {
  padding-top: 8px;
  .form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr; /* 多列对齐布局 */
    gap: 12px 20px;
  }
  .range-inputs {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    .range-sep { color: #666; }
    .range-unit { color: #666; font-size: 12px; }
    :deep(.el-input) { max-width: 120px; }
  }
}

.config-section {
  .config-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 15px;
    padding: 10px 0;
    border-bottom: 1px solid #f0f0f0;
    
    &:last-child {
      border-bottom: none;
    }
    
    label {
      font-size: 14px;
      color: #333;
      min-width: 100px;
    }
    
    .threshold-inputs {
      display: flex;
      align-items: center;
      gap: 8px;
      
      span {
        color: #666;
        font-size: 12px;
      }
    }
  }
}

.system-info {
  background: #f8f9fa;
  border-radius: 8px;
  padding: 15px;
  
  .info-header {
    font-weight: 500;
    color: #333;
    margin-bottom: 15px;
    padding-bottom: 8px;
    border-bottom: 1px solid #e8e8e8;
  }
  
  .info-items {
    .info-item {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 8px 0;
      
      .info-label {
        font-size: 13px;
        color: #666;
      }
      
      .info-value {
        font-size: 13px;
        color: #333;
        font-weight: 500;
      }
    }
  }
}

/* 设备状态详情模块样式 */
.device-status-detail {
  .environment-params {
    display: flex;
    justify-content: space-around;
    margin-bottom: 30px;
    padding: 20px 0;
    
    .param-item {
      display: flex;
      flex-direction: column;
      align-items: center;
      text-align: center;
      
      .param-icon {
        width: 60px;
        height: 60px;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        margin-bottom: 10px;
        
        i {
          font-size: 24px;
          color: white;
        }
      }
      
      .param-content {
        .param-value {
          font-size: 18px;
          font-weight: bold;
          color: #333;
          margin-bottom: 5px;
        }
        
        .param-label {
          font-size: 14px;
          color: #666;
        }
      }
      
      &.temperature .param-icon {
        background: linear-gradient(135deg, #67C23A, #85CE61);
      }
      
      &.humidity .param-icon {
        background: linear-gradient(135deg, #409EFF, #66B1FF);
      }
      
      &.pm25 .param-icon {
        background: linear-gradient(135deg, #67C23A, #85CE61);
      }
    }
  }
  
  .gas-indicators {
    .gas-item {
      display: flex;
      align-items: center;
      margin-bottom: 15px;
      
      .gas-label {
        width: 60px;
        font-size: 14px;
        color: #333;
        font-weight: 500;
      }
      
      .gas-bar {
        flex: 1;
        height: 8px;
        border-radius: 4px;
        overflow: hidden;
        margin-left: 15px;
        
        .gas-progress {
          height: 100%;
          border-radius: 4px;
          transition: width 0.3s ease;
        }
      }
      
      &:nth-child(1) {
        .gas-bar {
          background-color: rgba(103, 194, 58, 0.2);
        }
        .gas-progress {
          background: linear-gradient(90deg, #67C23A, #85CE61);
        }
      }
      
      &:nth-child(2) {
        .gas-bar {
          background-color: rgba(230, 162, 60, 0.2);
        }
        .gas-progress {
          background: linear-gradient(90deg, #E6A23C, #F7BA2A);
        }
      }
      
      &:nth-child(3) {
        .gas-bar {
          background-color: rgba(245, 108, 108, 0.2);
        }
        .gas-progress {
          background: linear-gradient(90deg, #F56C6C, #F78989);
        }
      }
      
      &:nth-child(4) {
        .gas-bar {
          background-color: rgba(245, 108, 108, 0.2);
        }
        .gas-progress {
          background: linear-gradient(90deg, #F56C6C, #F78989);
        }
      }
    }
  }
}

/* 温湿度图表样式 */
.temperature-humidity-chart {
  .temp-hum-chart-container {
    height: 200px;
    margin-bottom: 15px;
  }
  
  .temp-hum-chart {
    width: 100%;
    height: 100%;
  }
  
  .temp-hum-stats {
    display: flex;
    gap: 20px;
    
    .stat-group {
      flex: 1;
      display: flex;
      flex-direction: column;
      gap: 10px;
    }
    
    .stat-item {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 8px 12px;
      border-radius: 6px;
      
      &.temperature {
        background: linear-gradient(135deg, #ff6b6b20, #ff6b6b10);
        border-left: 3px solid #ff6b6b;
      }
      
      &.humidity {
        background: linear-gradient(135deg, #4ecdc420, #4ecdc410);
        border-left: 3px solid #4ecdc4;
      }
      
      .stat-label {
        font-size: 12px;
        color: #666;
      }
      
      .stat-value {
        font-size: 14px;
        font-weight: 600;
        color: #333;
      }
    }
  }
}

/* 响应式设计 */
@media (max-width: 1200px) {
  .monitor-grid {
    grid-template-columns: 1fr;
    grid-template-rows: repeat(4, auto);
    height: auto;
  }
  
  .grid-item {
    min-height: 400px;
  }
}

@media (max-width: 768px) {
  .cloudmeter-monitor {
    padding: 10px;
  }
  
  .page-header {
    flex-direction: column;
    gap: 10px;
    
    .header-actions {
      width: 100%;
      justify-content: center;
    }
  }
  
  .status-cards,
  .metrics-grid,
  .alarm-stats {
    grid-template-columns: 1fr;
  }
  
  .module-header {
    padding: 12px 15px;
    
    .header-controls {
      flex-direction: column;
      gap: 5px;
    }
  }
  
  .module-content {
    padding: 15px;
  }
}
</style>